
/**
 * broserslist 编译后适配版本写在package.json中
 * "browserslist": {
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ],
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ]
  }
 * 
*/

/**
 * babel
 * Babel 默认只转换新的 JavaScript 句法（syntax），而不转换新的 API，
 * 比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象，
 * 以及一些定义在全局对象上的方法（比如 Object.assign）都不会转码。
    转译新的 API，需要借助polyfill方案去解决，
    使用@babel/polyfill或@babel/plugin-transform-runtime，二选一即可。
    https://segmentfault.com/a/1190000020237790
*/

/**
 * HMR 开发模式时用，生产模式时候不需要
 * HMR :hot module replacement 热模块替换/模块热替换
 *  作用；一个模块变化，只会重新打包这个模块，不会打包所有，提升构建速度
 *  样式文件：可以使用，因为style-loader内部实现了
 *  js文件：默认没用hmr功能
 *       解决：在index.js根文件里配置module.hot,根文件是做不了HMR功能得
 *  html：默认没用hmr功能，html文件不能热更新了(不需要做，就一个html文件)
 *      解决：entry改成数组，将html文件引入
 * */ 

/**
 * source-map：是一种提供源代码到构建后代码映射得技术
 * （如果构建后代码出错了，通过映射可以追踪到源代码错误）devtool:'source-map'
 * [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
 *    source-map 外部 
 *      提供错误代码得准确信息
 *    inline-source-map 内联，在bundle.js里面生成 构建速度更快  只生成1个source-map
 *    hidden-source-map 外部，会生成bundle.js.map文件
 *      提供错误代码错误原因，但是没用错误位置，不能追踪到源代码得错误，只能提示到构建代码得位置
 *    eval-source-map 内联 每个文件都生成一个source-map并第都在eval中
 *    nosources-  外部
 *      提供信息，位置加哈希值，防止找源码
 *    cheap-      外部
 *      提供错误信息，精确到行
 *    cheap-module- 外部
 * 
 * 开发环境：速度快，调试更友好 
 *    速度快：eval>inline>cheap>...
 *           eval-cheap-source-map
 *           eval-source-map
 *    调试更友好：
 *           source-map
 *           cheap-module-source-map
 *           cheap-source-map
 *    -->eval-source-map  脚手架里面默认使用得
 * 
 * 生产环境：源代码是否隐藏，调试友好程度
 *    内联会让代码体积变大，所以生产环境下不用内联得
 *    hidden-source-map 全部隐藏
 *    nosources-source-map 只隐藏源代码，会提示构建代码错误
 *    --> source-map / 
 *  */ 

/**
 * 缓存
 * babel缓存（生产模式），js大头代码编译处理，100模块，一个模块变，99个不变用缓存 cacheDirectory:true
 * 文件资源缓存，（修改文件名）强缓存会有个问题，修改编译后不会再更新，给js和css添加哈希值，会有个问题
 *              hash每次构建都生成不一样的。当css和js同时设置hash，只修改js，另一个css缓存也失效
 *              解决：chunkhash：打包来自于同一个chunk那么哈希值就一样
 *              修改后问题：js和css的hash值还是一样的
 *              解决：因为css在js中引入，同属于一个chunk所以这个不行
 *              解决2：contenthash： 根据文件的内容生成hash值 ，用于上线代码优化的
*/

/**
 * tree shaking 树摇，无用的代码去除掉（js，css）
 * 前提：1.必须es6模块化2.开启mode：production环境
 * 例如我有个a模块引入另一个b模块，b模块里有未被使用的方法，那么在打包编译a模块时，不打包b中无用模块
 * 作用：减少代码体积
 *   "sideEffects":false,在packagejson中配置，表示所有代码没有副作用（都可以进行tree shaking）
 *    问题：可能会把css/  @babel/polyfill 干掉
 *    解决："sideEffects":["*.css"] css就不会死了，把不要tree shaking得配置进去 css less 
*/

/**
 * code split 代码分割， 把一个tunk文件分割成多个文件，并行加载，加载速度更快 （）
 * 分割方法1：修改entry入口和output出口
 * 有一个入口，最终输出就有一个built，有两个entry入口，输出两个，注意要加contenthash命名才会output两个，
 *  如果输出两个，那么都叫bundle可以改下  
 *      filename:'js/bundle.[chunkhash:10].js' --》 filename:'js/[name].[chunkhash:10].js', 可以取entry【key】文件名
 *  多页面项目注意多入口
 * 
 * 分割方法2：添加配置
 * 可以将node_modules中代码单独打包成一个chunk最终输出，和entry的chunk不冲突
 * optimization:{
    splitChunks:{
      chunks:'all'
    }
    作用
      1.将第三方的包和本地分开，例如入口引入jquery，会单独生成一个，本地生成一个
      2.如果多入口都引入包，则此包只会生成一次，属于公共文件，只会生成一个chunk包
  }

  分割方法3：import 动态导入  通过js代码让某个文件被单独打包成一个chunk
  例如a模块引入b模块，单个入口，我就想b单独打包出来，作用就是将某个文件单独打包，例入vue-router里的打包,前面是命名
 * import(/* webpackChunkName:'b' */ /*'./b').then(({result})=>{
   文件加载成功
  }).catch(()=>{文件加载失败})
*/

/**
 * lazy loading 懒加载预加载（js文件）
 * 
 * 例如点击时候再加载js文件
 * a.click = function (){
 *    import(/ * webpackChunkName:''test,webpackPrefetch:true* /'./test').then(({mul})=>{  
 *      console.log(mul(4,5))
 *    })
 * }
 * 懒加载
 * 把满足的代码，放在一个异步的函数中，执行才去加载，加载过后，从缓存加载，如果文件体积过大，要等较长时间反应
 * 预加载
 * webpackPrefetch，会把test.js先加载好，点击时候，会生成同一个js读的前面预加载好的js（缺点api兼容性差）
 * 预和正常的区别：正常加载时可以认为是并行加载（同一时间加载多个文件，如果某个文件一开始不需要，加载了浪费时间），
 * ·              而预加载是等其他资源加载完毕，浏览器空闲了再偷偷加载资源
 * 
*/

/**
 * PWA 渐进式网络开发应用程序，离线网站也能访问，network online改成offline
 * workbox --》 work-webpack-plugin 插件
 * 
*/

/**
 * 多进程
 * thread-loader给babel用
 * 对于比较大的包用多进程并行快，如果小的包，适得其反，启动它也要耗时
*/

/**
 * externals，通过cdn访问而不是包引入
 * 在html里引入cdn
*/

/**
 * dll 拆库（第三方库）打包成不同的chunk
 * 使用dll技术对某些库进行单独打包
*/

const {resolve} = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// const CopyWebpackPlugin = require("copy-webpack-plugin")
const OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin")
const {CleanWebpackPlugin} = require("clean-webpack-plugin")

//设置nodejs环境变量  "browserslist"默认使用生产环境配置
// process.env.NODE_ENV="development"

module.exports={
  entry:'./src/js/index.js',//{main:'./src/js/index.js',test:"./xxx.js"} 可以引入两个模块，多入口模式使用多页面应用
  output:{
    filename:'js/bundle.[chunkhash:10].js',    //添加哈希值，因为babel设置了强缓存，修改webpack后还是取缓存，加hash用于区分
    path:resolve(__dirname,"public")
  },
  module:{
    rules:[
      // oneOf:[] //如果再加一层，把下面得塞进去，那么下面loader只会匹配一个，注意：不能有两个配置处理同一种类型文件

      {
        test:/\.css$/,
        use:[
          // 'style-loader',
          MiniCssExtractPlugin.loader, //使用插件将css从js中提取出来（css提取）。生产模式提取，开发模式用HMR，style-loader支持
          //importLoaders的意思是如果css-loader处理了，没法往回找到postcss-loader再进行适配，所以它是几往回找几个loader开始执行
          //例如@import css 这个是在css-loader执行的。
          {
            loader:'css-loader',
            // options:{
              //   importLoaders:1  
              // }
          },
          /**
           * css兼容性处理（css适配）， postcss库 -> postcss-loader  postcss-preset-env插件 识别browser环境加载配置，
           */
          //使用loader默认配置
          "postcss-loader",
          // 修改loader配置
          //有很多插件，postcss-preset-env是内置的，包含了autoprefixer并且能做更多事
          //但是有个问题每个loader都写一遍很麻烦，例如less也要加postcss，所以抽离出来
          // {
            //   loader:'postcss-loader',
            //   options:{
              //     postcssOptions:{
                //       plugins:[
                  //         // require('autoprefixer')
                  //         // require('postcss-preset-env')
                  //         //并不是所有的插件都可以简写，因为有些插件时需要传入额外的参数的，所以有些插件不能简写。
                  //         "postcss-preset-env" 
                  //       ]
                  //     }
                  //   }
                  // }
              ],
            },
            {
              test:/\.less$/,
              use:[ MiniCssExtractPlugin.loader,'css-loader','postcss-loader','less-loader'] //,'style-loader' 把他改成提取文件的minicss插件
            },
            {
              test:/\.(jpg|png|gif)$/,
              loader:'url-loader',
        options:{
          limit:8*1024, //小的图片转成base64，大的图片原样复制过去就行，不然大的图片太大，打包后的js也会变成非常大，到时候请求就非常慢
          name:"[hash:10].[ext]",  //保留图片hash10个字母
          // esModule:false,      //启用commonjs编译不用es6模块
          outputPath:'imgs'
        },
      },
      {
        test:/\.html$/,      //debuger html引入的图片不好使后面查一下
        loader:'html-loader',
      },
      {
        exclude:/\.(html|js|css|less|jpg|png|gif|html)$/,
        loader:'file-loader',
        options:{
          // name:"[hash:10].[ext]",
          // outputPath:'media'
          name:"media/[hash:10].[ext]" //简写
        },
      },
      
      //eslint语法检测
      // {
        //   test:/\.js$/,
        //   exclude:/node_modules/, //eslint语法检查，排除node_modules
        //   loader:'eslint-loader',
        //   options:{}
        // }
        
        //css
        // {
          //   test: /\.(css|scss)$/,
          //   use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']
          // }
          
          //es6->es5 同时做兼容性处理
          //npm i  babel-loader @babel/core @babel/preset-env -D 
          //上面的只能转化基础的，但是promise不行
          //1强制全部引入  @babel/polyfill包 不需要配置直接index.js里import ‘@babel/polyfill’，缺点太大，最后按需加载
          //2按需加载引入 core-js
      {
        test:/\.js$/,
        exclude:/node_modules/,
        use:[
          //开启多进程打包，启动进程大概为600ms，进程通信也有开销
          {
            loader:"thread-loader",
            options:{
              workers:2 //进程2个
            }
          },
          {
            loader:"babel-loader",
            options:{
              //babel缓存，第二次构建时按需编译加载
              "cacheDirectory":true
            //   presets:[
            //     // '@babel/preset-env',
            //     [
            //       '@babel/preset-env',
            //       {
            //         useBuiltIns:'usage', //按需加载
            //         corejs:{             //指定版本
            //           version:3
            //         },
            //         targets:{            //指定兼容性到哪个版本浏览器
            //           chrome:"60",
            //           firefox:"50",
            //           ie:"9",
            //           safari:"10",
            //           edge:"17"
            //         }
            //       }
            //     ],
            //   ],
            //   //babel缓存，第二次构建时按需编译加载
            //   cacheDirectory:true
            //   // "plugins":["@babel/plugin-transform-runtime"] 
            }

          }
        ]
        
      }
    ]
  },
  plugins:[
    //使用的是ejs模板语法，源码里的"<%= %>"是准备给值代替的，传值进去
    new HtmlWebpackPlugin({
      title:"mcgeehhh",
      template:'./src/index.html',  //配置自己的模板
      //压缩html代码
      minify:{
        collapseWhitespace:true, //移除空格
        removeComments:true //移除注释
      }
    }),
    new MiniCssExtractPlugin({
      filename:'css/built.[chunkhash:10].css'  //摘取出来生成css目录
    }),
    new OptimizeCssAssetsWebpackPlugin(),//压缩css,
    // new CleanWebpackPlugin(),
    
  ],
  //改成production 压缩js代码development
  mode:'development',
  devServer:{
    contentBase: './public',//resolve(__dirname,'public'),
    host:'localhost',
    port:'3000',
    open:true,
    hot:true, //开启hmr功能
  },
  /**
   * 配置了browserslist 选项，而windows上并没有写这一项配置，而正是由于这个坑爹的选项，导致了问题的出现，删除掉这个选项，
      经过百度之后得知，这是个bug，目前还没有修复，但可以通过设置 target: "web" 来暂时解决
  */
  target:"web",
  devtool:'eval-source-map',
  // optimization:{
  //   splitChunks:{
  //     chunks:'all'
  //   }
  // }
  externals:{
    //忽略的库名：npm包名（拒绝jquery被打包进来）
    jquery:'jQuery'
  }
}